﻿using UnityEngine;

//------------------------------------------------------------
// shaco Framework
// Copyright © 2017-2025 chang.liu All rights reserved.
// Feedback: 449612236@qq.com
//------------------------------------------------------------

namespace shaco
{
    static public class ExtensionsRenderer
    {
        static public bool Intersects(this Renderer r1, Renderer r2)
        {
            bool retValue = CheckOBBIntersection(r1.transform, r2.transform, r1.localBounds, r2.localBounds);
            return retValue;
        }

        static public bool Intersects(this Transform r1, Transform r2, Bounds localBounds1, Bounds localBounds2)
        {
            bool retValue = CheckOBBIntersection(r1.transform, r2.transform, localBounds1, localBounds2);
            return retValue;
        }

        static bool CheckOBBIntersection(Transform t1, Transform t2, Bounds localBounds1, Bounds localBounds2)
        {
            // 获取OBB顶点（基于本地包围盒）
            Vector3[] GetOBBVertices(Transform t, Bounds localBounds)
            {
                Vector3[] vertices = new Vector3[8];
                Vector3 center = localBounds.center;
                Vector3 extents = localBounds.extents;

                vertices[0] = t.TransformPoint(center + new Vector3(-extents.x, -extents.y, -extents.z));
                vertices[1] = t.TransformPoint(center + new Vector3(extents.x, -extents.y, -extents.z));
                vertices[2] = t.TransformPoint(center + new Vector3(extents.x, extents.y, -extents.z));
                vertices[3] = t.TransformPoint(center + new Vector3(-extents.x, extents.y, -extents.z));
                vertices[4] = t.TransformPoint(center + new Vector3(-extents.x, -extents.y, extents.z));
                vertices[5] = t.TransformPoint(center + new Vector3(extents.x, -extents.y, extents.z));
                vertices[6] = t.TransformPoint(center + new Vector3(extents.x, extents.y, extents.z));
                vertices[7] = t.TransformPoint(center + new Vector3(-extents.x, extents.y, extents.z));

                return vertices;
            }

            Vector3[] aVertices = GetOBBVertices(t1, localBounds1);
            Vector3[] bVertices = GetOBBVertices(t2, localBounds2);

            // 分离轴定理实现
            bool SATTest(Vector3[] vertsA, Vector3[] vertsB)
            {
                // 获取所有可能的分离轴
                Vector3[] GetAxes(Vector3[] vertsA, Vector3[] vertsB)
                {
                    Vector3[] axes = new Vector3[15];

                    // 第一个OBB的面法线
                    Vector3 aRight = t1.right;
                    Vector3 aUp = t1.up;
                    Vector3 aForward = t1.forward;

                    // 第二个OBB的面法线
                    Vector3 bRight = t2.right;
                    Vector3 bUp = t2.up;
                    Vector3 bForward = t2.forward;

                    // 交叉积轴
                    axes[0] = Vector3.Cross(aRight, bRight).normalized;
                    axes[1] = Vector3.Cross(aRight, bUp).normalized;
                    axes[2] = Vector3.Cross(aRight, bForward).normalized;
                    axes[3] = Vector3.Cross(aUp, bRight).normalized;
                    axes[4] = Vector3.Cross(aUp, bUp).normalized;
                    axes[5] = Vector3.Cross(aUp, bForward).normalized;
                    axes[6] = Vector3.Cross(aForward, bRight).normalized;
                    axes[7] = Vector3.Cross(aForward, bUp).normalized;
                    axes[8] = Vector3.Cross(aForward, bForward).normalized;

                    // 面法线轴
                    axes[9] = aRight;
                    axes[10] = aUp;
                    axes[11] = aForward;
                    axes[12] = bRight;
                    axes[13] = bUp;
                    axes[14] = bForward;

                    return axes;
                }

                Vector3[] axes = GetAxes(vertsA, vertsB);

                foreach (Vector3 axis in axes)
                {
                    if (axis.sqrMagnitude < 0.001f) continue;

                    // 计算投影范围
                    void ProjectVertices(Vector3[] verts, Vector3 axis, out float min, out float max)
                    {
                        min = float.MaxValue;
                        max = float.MinValue;
                        foreach (Vector3 vert in verts)
                        {
                            float proj = Vector3.Dot(vert, axis);
                            min = Mathf.Min(min, proj);
                            max = Mathf.Max(max, proj);
                        }
                    }

                    ProjectVertices(vertsA, axis, out float aMin, out float aMax);
                    ProjectVertices(vertsB, axis, out float bMin, out float bMax);

                    // 检查投影是否重叠
                    if (aMax < bMin || bMax < aMin)
                        return false;
                }
                return true;
            }

            return SATTest(aVertices, bVertices);
        }
    }
}